<template>
  <div>
    <div ref="zz" class="ct-slot-style">
      <slot name="trackMarkerInfoWindow" :data="slotData">
      </slot>
    </div>
  </div>
</template>

<script>

import * as maptalks from 'maptalks';
import {Coordinate} from 'maptalks';

export default {
  name: 'ctMapTrack',
  components: {},
  props: {
    pointOfTrack: {
      type: Array,
      default() {
        /**
         * 元素结构 如下（必须包含xy属性）
         * [
         *   {
         *   x:126.45612,
         *   y:45.12345
         *   },
         *   {
         *   x:126.45612,
         *   y:45.12345
         *   }
         * ]
         */
        return [];
      },
    },
    action: {
      type: String,
      default() {
        /**
         * 字符串类型
         * 'pause'  暂停
         * 'play'   播放
         * 'reset'  重置
         */
        return ''
      }
    },
    playSpeed: {
      type: Number,
      default() {
        // 越大越慢
        return 1000
      }
    },
    offsetIndex: {
      type: Number,
      default() {
        return null
      }
    },
    pointSymbol: {},
    lineSymbol: {},
    showInfoWindow: {
      type: Boolean,
      default() {
        return false
      }
    },
    markerListensEnable: {
      type: String,
      default() {
        return '';
      },
    },
  },
  data: () => ({
    // 动画 “片段” 的初始索引
    index: 0,
    // 动画 “片段” 的索引 。解释：用来计算 轨迹 动画使用，所谓片段 即 两个点之间的 marker移动的动画， 因为轨迹是由很多个点组成，所以它有很多个动画片段. 三个点 两个动画片段  动画的索引为 0和1 ，即最大动画索引为 1
    indexMax: null,
    // 很重要的属性！！，所有渲染都是基于此属性。 经过坐标转换后的集合，因为点都是要和坐标系统一 ***** 单个对象包含 坐标点，标注图片，图片角度。。。等等
    coordinateList: [],
    // 当前时间 正在执行的动画的 播放器对象
    currentAnimateObj: null,
    slotData: '999',
    currentPlayStatus: 'pause' //内部维护的一个动画状态， 4种状态  pause  playing  reset  finish
  }),
  created() {
  },
  mounted() {
    const vue = this;
    this.$nextTick(() => {
      const {firstLayer} = this.$parent
      //为 元素对象 添加 transformedCoordinate属性（标准坐标类型 new Coordinate() ），返回处理后的数组
      this.coordinateList = this.localTransformXyBatch(this.pointOfTrack)
      if (vue.coordinateList.length !== 0) {
        vue.doRender(firstLayer, vue.index).pause()
      } else {
        firstLayer.clear()
        this.$emit('nullException')
      }
    });
  },
  methods: {
    // 首次渲染
    doRender(layer, startIndex) {
      const vue = this;
      // 先清除图层，在从新画图
      layer.clear()
      vue.indexMax = vue.coordinateList.length - 2;
      // 绘制 道路
      vue.doRenderRoad(layer)
      // 绘制移动的点 的动画
      return vue.doRenderMarkerAnimate(layer, startIndex)
    },
    // 渲染道路
    doRenderRoad(layer) {
      const vue = this;
      const multiLineString = vue.createMultiLineStringObj(vue.coordinateList);
      multiLineString.addTo(layer);
      // 把路线渲染事件 冒泡 到 父组件
      vue.$emit('multiLineGeometry', multiLineString)
    },
    // 渲染 marker 动画
    doRenderMarkerAnimate(layer, startIndex) {
      const vue = this
      let startData = vue.coordinateList[startIndex];
      const startMarker = this.createMarkerObj(startData, 'moveMarker');
      const startCoordinate = startData.transformedCoordinate;
      if (startData.markerSymbol) {
        startMarker.setSymbol(startData.markerSymbol)
      }
      // 2.设置 infoWindow ， 但是 还未 show in map
      let slots = vue.$scopedSlots.trackMarkerInfoWindow
      if (slots) {
        // startData.infoWindow.content = vue.$refs.zz
        startMarker.setInfoWindow(startData.infoWindow);
      }
      // 3.是否展示 infowindow
      if (this.showInfoWindow) {
        startMarker.openInfoWindow()
      } else {
        startMarker.closeInfoWindow()
      }
      // 4. 添加事件监听 一般是 click
      if (vue.markerListensEnable) {
        let events = vue.markerListensEnable.toString().replaceAll(',', ' ')
        startMarker.on(events, (param) => {
          if (param.type === 'click') {
            vue.$emit('markerClick', param.target, vue.coordinateList[vue.index])
          } else {
            vue.$emit('markerNotClick', param, vue.coordinateList[vue.index])
          }
        });
      }
      //1.将新生成的 标注 放到 图层上
      startMarker.addTo(layer);
      //2.是否可以创建 标注的动画 对象
      if (startIndex + 1 <= this.coordinateList.length - 1) {
        const endCoordinate = vue.coordinateList[startIndex + 1].transformedCoordinate;
        const offset = vue.getOffset(startCoordinate, endCoordinate);
        vue.currentAnimateObj = vue.createAnimateObj(startMarker, startCoordinate, offset);
        return vue.currentAnimateObj
      } else {
        const offset = vue.getOffset(startCoordinate, startCoordinate);
        vue.currentAnimateObj = vue.createAnimateObj(startMarker, startCoordinate, offset);
        return vue.currentAnimateObj
      }
    },
    play(play) {
      play.play()
    },
    pause(play) {
      play.pause()
    },
    /**
     * 根据 当前图层 和 当前点类型 进行 批量坐标转换 ，增加一个属性， 适配当前图层的坐标 （转换后的）
     * @param originalPointList  含有车辆业务数据对象
     * @returns [{}]
     */
    localTransformXyBatch(originalPointList) {
      const arr = [];
      originalPointList.forEach((originalPoint) => {
        let proxyPoint = []
        proxyPoint.push(originalPoint.x)
        proxyPoint.push(originalPoint.y)
        originalPoint.transformedCoordinate = new Coordinate(proxyPoint)
        arr.push(originalPoint);
      });
      return arr
    },
    createMultiLineStringObj(pointOfTrack) {
      const arr = [];
      for (let i = 0; i < pointOfTrack.length - 1; i++) {
        const subArr = [];
        subArr.push(pointOfTrack[i]);
        subArr.push(pointOfTrack[i + 1]);
        arr.push(subArr);
      }
      return new maptalks.MultiLineString(
        arr,
        {
          arrowStyle: null, // arrow-style : now we only have classic
          arrowPlacement: 'vertex-last', // arrow's placement: vertex-first, vertex-last, vertex-firstlast, point
          visible: true,
          editable: true,
          cursor: null,
          shadowBlur: 0,
          shadowColor: 'black',
          draggable: false,
          dragShadow: false, // display a shadow during dragging
          drawOnAxis: null, // force dragging stick on a axis, can be: x, y
          symbol: this.lineSymbol !== null ? this.lineSymbol : {
            lineColor: '#1bbc9b',
            lineWidth: 3,
          },
        },
      ).setId('road');
    },
    createMarkerObj(point, markerId) {
      if (markerId) {
        const {firstLayer} = this.$parent
        let geometryById = firstLayer.getGeometryById(markerId)
        if (geometryById) {
          firstLayer.removeGeometry(markerId)
        }
      }
      const marker = new maptalks.Marker(point)
      if (this.pointSymbol) {
        marker.setSymbol(this.pointSymbol);
      }
      if (markerId) {
        marker.setId(markerId)
      }
      return marker;
    },
    createAnimateObj(marker, start, offset) {
      marker.setCoordinates(start);
      let options = {
        duration: this.playSpeed,
        focus: true,
      }
      let keyframes = {translate: offset}
      return marker.bringToFront().animate(keyframes, options, this.animateCbFn)
    },
    getOffset(start, end) {
      return end.sub(start);
    },
    /**
     * 动画回调函数
     */
    animateCbFn(frame) {
      const _this = this
      if (frame.state.playState === 'finished' && _this.currentPlayStatus === 'playing') {
        _this.index++
        let flag = _this.index + 1 <= _this.coordinateList.length - 1;
        if (flag) {
          let ss = _this.coordinateList[_this.index]
          let ee = _this.coordinateList[_this.index + 1]
          const s = ss.transformedCoordinate;
          const e = ee.transformedCoordinate;
          const o = _this.getOffset(s, e);
          // 1.设置标注样式
          if (ss.markerSymbol) {
            marker.setSymbol(ss.markerSymbol)
          }
          // 2.设置 infoWindow
          let slots = _this.$scopedSlots.trackMarkerInfoWindow
          if (slots) {
            // ss.infoWindow.content = _this.$refs.zz
            marker.setInfoWindow(ss.infoWindow);
          }
          // 3.是否显示 infoWindow
          if (_this.showInfoWindow) {
            marker.openInfoWindow()
          } else {
            marker.closeInfoWindow()
          }
          _this.currentAnimateObj = _this.createAnimateObj(marker, s, o);
          _this.$emit('updateSlotDom', ss)
          _this.$emit('playStatus', _this.currentPlayStatus)
        } else {
          // 播放完毕
          _this.currentPlayStatus = 'finish'
          _this.$emit('playStatus', _this.currentPlayStatus)
        }
      }
    }
  },
  computed: {},
  watch: {
    action: {
      handler: function (v) {
        const vue = this
        const {firstLayer} = this.$parent
        if (this.coordinateList.length === 0) {
          return
        }
        switch (this.action) {
          case 'pause':
            // 暂停播放
            if (vue.currentAnimateObj) {
              vue.currentPlayStatus = 'pause'
              vue.currentAnimateObj.pause()
            }
            vue.$emit('playStatus', vue.currentPlayStatus)
            break
          case 'play':
            // 播放
            if (vue.currentAnimateObj) {
              if (vue.index >= this.coordinateList.length - 1) {
                vue.currentPlayStatus = 'pause'
                vue.$emit('playStatus', vue.currentPlayStatus)
                return
              } else {
                vue.currentPlayStatus = 'playing'
                vue.currentAnimateObj.play()
                vue.$emit('playStatus', vue.currentPlayStatus)
              }
            } else {
              vue.currentPlayStatus = 'pause'
              vue.$emit('playStatus', vue.currentPlayStatus)
            }
            break
          case 'reset':
            vue.currentPlayStatus = 'pause'
            // 先结束动画
            vue.currentAnimateObj.finish()
            // 重置 索引
            vue.index = 0
            // 重新新渲染 动画， 先渲染第一个点到第二个点得动画对象，并且暂停它
            let currentIndexAnimateObj = vue.doRenderMarkerAnimate(firstLayer, vue.index);
            currentIndexAnimateObj.pause()
            //
            vue.$emit('playStatus', vue.currentPlayStatus)
            break
          default:
            break
        }
      },
    },
    pointOfTrack: {
      handler: function (v) {
        const vue = this
        this.coordinateList = this.localTransformXyBatch(this.pointOfTrack)
        const {firstLayer} = this.$parent
        if (vue.coordinateList.length !== 0) {
          vue.index = 0
          vue.doRender(firstLayer, vue.index).pause()
        } else {
          firstLayer.clear()
          this.$emit('nullException')
        }
      },
    },
    playSpeed: {
      handler: function (v) {
        if (this.playSpeed >= 500 && this.playSpeed <= 2000) {
          this.currentAnimateObj.speed = this.playSpeed
        } else if (this.playSpeed < 500) {

          this.currentAnimateObj.speed = 500
        } else if (this.playSpeed > 2000) {
          this.currentAnimateObj.speed = 2000
        }
      },
    },
    offsetIndex: {
      handler: function (v) {
        const vue = this
        if (this.offsetIndex || this.offsetIndex === 0) {
          const {firstLayer} = this.$parent
          if (vue.currentPlayStatus === 'playing') {
            vue.$emit('notAllow', '[播放中]禁止该操作！')
            return
          }
          vue.index = vue.offsetIndex
          vue.currentAnimateObj = null
          // 从新渲染
          let currentAnimateObj = vue.doRenderMarkerAnimate(firstLayer, vue.index);
          currentAnimateObj.pause()
        }
      },
    },
  },
};
</script>

